package com.example.dml.factory_pattern.jdbc;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Date;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;

/**
 * @description: 数据库连接池管理类
 * @author: gaoyang
 * @date: 2021/10/22 00:42
 */
public final class DBConnectionPool extends Pool {

    //正在使用的连接数
    private int checkedOut;

    //存放产生的连接对象容器
    private Vector<Connection> freeConnections = new Vector<>();
    private String url = null;
    private String userName = null;
    private String passWord = null;
    private static int num = 0;
    private static int numActive = 0;
    private static DBConnectionPool pool = null;

    //产生数据连接池
    public static synchronized DBConnectionPool getInstance() {
        if (pool == null) {
            pool = new DBConnectionPool();
        }
        return pool;
    }

    //获得一个数据库连接池的实例
    private DBConnectionPool() {
        try {
            init();
            for (int i = 0; i < normalConnect; i++) {
                Connection c = newConnection();
                if (c != null) {
                    freeConnections.addElement(c);//往容器中添加一个连接对象
                    num++;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void init() throws IOException {
        InputStream is = DBConnectionPool.class.getResourceAsStream(propertiesName);
        Properties p = new Properties();
        p.load(is);
        this.userName = p.getProperty("userName");
        this.passWord = p.getProperty("passWord");
        this.driverName = p.getProperty("driverName");
        this.url = p.getProperty("url");
        this.maxConnect = Integer.parseInt(p.getProperty("maxConnect"));
        this.normalConnect = Integer.parseInt(p.getProperty("normalConnect"));
    }

    public synchronized void freeConnection(Connection con) {
        freeConnections.addElement(con);
        num++;
        checkedOut--;
        numActive--;
        notifyAll();//解锁
    }

    private Connection newConnection() {
        Connection con = null;
        try {
            if (userName == null) {//用户名密码都为空
                con = DriverManager.getConnection(url);
            } else {
                con = DriverManager.getConnection(url, userName, passWord);
            }
            System.out.println("连接池创建一个新的连接");
        } catch (Exception e) {
            System.out.println("无法创建这个url连接" + url);
            return null;
        }
        return null;
    }

    //返回当前空闲连接数
    public int getnum(){
        return num;
    }

    //返回当前连接数
    public int getnumActive(){
        return numActive;
    }

    //(单例模式)获取一个可用连接
    public synchronized Connection getConnection(){
        Connection con = null;
        if (freeConnections.size()>0){//还有空闲连接
            num--;
            con = freeConnections.firstElement();
            freeConnections.removeElementAt(0);
            try {
                if (con.isClosed()){
                    System.out.println("从连接池中删除一个无效连接");
                    con = getConnection();
                }
            }catch (Exception e){
                System.out.println("从连接池中删除一个无效连接");
            }
        }else if (maxConnect==0||checkedOut<maxConnect){
            con = newConnection();
        }
        if (con!=null){
            checkedOut++;
        }
        numActive++;
        return con;
    }

    //获取一个连接，并加上等待时间限制，单位为毫秒
    public synchronized Connection getConnection(long timeout){
        long startTime = new Date().getTime();
        Connection con;
        while ((con=getConnection())==null){
            try {
                wait(timeout);//线程等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if ((new Date().getTime()-startTime)>=startTime){
                return null;//如果超时，则返回
            }
        }
        return con;
    }

    public synchronized void release(){
        Enumeration allConnections = freeConnections.elements();
        while (allConnections.hasMoreElements()){
            Connection con = (Connection) allConnections.nextElement();
            try {
                con.close();
                num--;
            } catch (SQLException e) {
                System.out.println("无法关闭连接池中的连接");
            }
        }
        freeConnections.removeAllElements();
        numActive=0;
    }

    @Override
    public void createPool() {
        pool = new DBConnectionPool();
        if (pool!=null){
            System.out.println("创建连接池成功");
        }else {
            System.out.println("创建连接池失败");
        }
    }


    @Override
    public int getNum() {
        return 0;
    }

    @Override
    public int getNumActive() {
        return 0;
    }

}
